#ifndef __MAIN_FRAME_H__
#define __MAIN_FRAME_H__

#include <wx/wx.h>
#include <wx/aui/aui.h>
#include <wx/event.h>
#include <wx/timer.h>
#include <wx/xml/xml.h>
#include <thread>

#include "panel_logger.h"
#include "panel_reverb.h"
#include "panel_equalizer.h"
#include "panel_chorus.h"
#include "panel_delay.h"
#include "panel_wah.h"
#include "panel_distortion.h"
#include "panel_preset.h"
#include "panel_compressor.h"
#include "MyCommon.h"
#include "USBCommunication.h"
#include "CommandProcess.h"
#include "ctrl_knob.h"
#include "DataSave.h"

#if defined __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/usb/IOUSBLib.h>
#include <IOKit/IOKitLib.h>
#endif

#define PANEL_EN_REVERB        1
#define PANEL_EN_CHORUS        1
#define PANEL_EN_DELAY         1
#define PANEL_EN_DISTORTION    1
#define PANEL_EN_COMPRESSOR    1
#define PANEL_EN_EQUALIZER     0
#define PANEL_EN_LOGGER        1
#define PANEL_EN_WAH           1
#define PANEL_EN_PRESET        0


// 定义自定义事件类
class MyEventMainFrame : public wxCommandEvent {
public:
    MyEventMainFrame(wxEventType eventType = wxEVT_NULL,int id = wxID_ANY)
        : wxCommandEvent(eventType, id) {

    }

    // 克隆事件对象
//    [[nodiscard]] // C++17 才支持，意思就是函数返回值不能被忽略，否则编译器发出警告
    virtual wxEvent *Clone() const override {
        return new MyEventMainFrame(*this);
    }

    void SetUSB_VID(int vid) {
        usb_vid = vid;
    }

    void SetUSB_PID(int pid) {
        usb_pid = pid;
    }

    void SetUSB_SerialNumber(wxString name) {
        usb_device_serial = name;
    }

    void SetProgress(int prog) {
        progress = prog;
    }

    int GetUSB_VID() {
        return usb_vid;
    }

    int GetUSB_PID() {
        return usb_pid;
    }

    wxString GetUSB_SerialNumber() {
        return usb_device_serial;
    }

    int GetProgress() {
        return progress;
    }

private:

    int usb_vid;
    int usb_pid;
    wxString usb_device_serial;
    int progress;

};

wxDECLARE_EVENT(mEVT_DEVICE_ARRIVAL, MyEventMainFrame);
wxDECLARE_EVENT(mEVT_DEVICE_REMOVED, MyEventMainFrame);
wxDECLARE_EVENT(mEVT_MAINFRAME_PROGRESS, MyEventMainFrame);


typedef void (wxEvtHandler::*MyMainFrameEventFunction)(MyEventMainFrame &);

#define MyMainFrameEventHandler(func) \
    wxEVENT_HANDLER_CAST(MyMainFrameEventFunction, func)

#define M_EVT_MAINFRAME_ARRIVAL(id, fn) \
    wx__DECLARE_EVT1(mEVT_DEVICE_ARRIVAL, id, MyMainFrameEventHandler(fn))
#define M_EVT_MAINFRAME_REMOVED(id, fn) \
    wx__DECLARE_EVT1(mEVT_DEVICE_REMOVED, id, MyMainFrameEventHandler(fn))
#define M_EVT_MAINFRAME_PROCESS(id, fn) \
    wx__DECLARE_EVT1(mEVT_MAINFRAME_PROGRESS, id, MyMainFrameEventHandler(fn))


#define ID_PANEL_REVERB         ID_START_PANEL_REVERB
#define ID_PANEL_EQUALIZER      ID_START_PANEL_EQUALIZER
#define ID_PANEL_CHORUS         ID_START_PANEL_CHORUS
#define ID_PANEL_DELAY          ID_START_PANEL_DELAY
#define ID_PANEL_DISTORTION     ID_START_PANEL_DISTORTION
#define ID_PANEL_COMPRESSOR       ID_START_PANEL_COMPRESS
#define ID_PANEL_WAH            ID_START_PANEL_WAH
#define ID_PANEL_PRESET         ID_START_PANEL_PRESET

class MainFrame : public wxFrame
{
public:
    enum
    {
        ID_TIM_USB_DELAY = ID_START_MAINFREAM,
        ID_DIALOG_PROCESS,
        ID_PANEL_EFFECT_PARAM,
        ID_MENU_VIEW_LOG,
        ID_MENU_VIEW_REVERB,
        ID_MENU_VIEW_EQUALIZER,
        ID_MENU_VIEW_CHORUS,
        ID_MENU_VIEW_DELAY,
        ID_MENU_VIEW_DISTORTION,
        ID_MENU_VIEW_OVERDRIVE,
        ID_MENU_VIEW_COMPRESS,
        ID_MENU_VIEW_WAH,
        ID_MENU_VIEW_PRESET,
        ID_PANEL_LOG,
    };
public:
    MainFrame();
    ~MainFrame();

private:
#if PANEL_EN_LOGGER
    PanelLogger *panel_log;
#endif
#if PANEL_EN_REVERB
    PanelReverb *panel_reverb;
#endif
#if PANEL_EN_CHORUS
    PanelChorus *panel_chorus;
#endif
#if PANEL_EN_DELAY
    PanelDelay *panel_delay;
#endif
#if PANEL_EN_DISTORTION
    PanelDistortion *panel_distortion;
#endif
#if PANEL_EN_COMPRESSOR
    PanelCompressor *panel_compress;
#endif
#if PANEL_EN_EQUALIZER
    PanelEqualizer *panel_eq;
#endif
#if PANEL_EN_WAH
    PanelWah *panel_wah;
#endif
#if PANEL_EN_PRESET
    PanelPreset *panel_preset;
#endif
    //MyKnob *panel_knob;

    wxAuiManager *auiManager;
    wxMenuBar *menuBar;
    wxTimer *tim_usb_delay;
    USBCommunication *usb_comm;
    CommandProcess *cmd_proc;

    MyEventMainFrame mainframe_event;
    ProgressDialog *proc_dig;
    unsigned int usb_device_pid;
    unsigned int usb_device_vid;
    unsigned char usb_device_in_ep;
    unsigned char usb_device_out_ep;
    char usb_device_interface_num;
    // std::thread thread_sync_data;
    // wxXmlDocument xmlConfig;
    // wxXmlNode *xmlConfigNodeReverb;
    // wxXmlNode *xmlConfigNodeChorus;
    // wxXmlNode *xmlConfigNodeDelay;
    // wxXmlNode *xmlConfigNodeDistortion;
    DataSave *data_save;

    int current_preset_num;

    wxString windowTitle;

    wxString config_file_full_path;
    const char *config_file_name = CONFIG_XML_FILE_NAME;

protected:

#if defined _WIN32
    virtual WXLRESULT MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam);
#endif
    bool RegisterUSBDeviceNotification(void);

private:

#if defined __APPLE__
    IONotificationPortRef notify_prot;
#endif

private:
    void OnHello(wxCommandEvent& event);
    void OnExit(wxCommandEvent& event);
    void OnClose(wxCloseEvent& event);
    void OnSaveParam(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);
    void OnMenuView(wxCommandEvent& event);
    void OnAUIPanelClose(wxAuiManagerEvent& event);
    void OnTimerUSBDelay(wxTimerEvent& event);
    void USBDeviceArrival(unsigned int vid, unsigned int pid,wxString serialNum);
    void USBDeviceRemove(unsigned int vid, unsigned int pid,wxString serialNum);
    void SyncDeviceData(void);
    void OnProcessUpdate(MyEventMainFrame& event);
    void OnUsbArrival(MyEventMainFrame& event);
    void OnUsbRemoved(MyEventMainFrame& event);

    void OnReverbParamChange(MyEventReverb &event);
    void OnChorusParamChange(MyEventChorus &event);
    void OnDelayParamChange(MyEventDelay &event);
    void OnWahParamChange(MyEventWah &event);
    void OnDistortionParamChange(MyEventDistortion &event);
    void OnCompressorParamChange(MyEventCompressor &event);
    void OnEqualizerParamChange(MyEventEqualizer &event);
    void OnPresetParamChange(MyEventPreset &event);

    // void initXmlConfigFile(wxString &file_full_path);
    // wxXmlNode *xmlFindChildNode(wxXmlNode *node, const char *name,bool autoCreate = true);
    // wxXmlAttribute *xmlFindNodeAttribute(wxXmlNode *node, const char *name);
    // bool xmlConfigSetValue(wxXmlNode *node, const char *attr_name, const char *value,bool autoCreate = true);
    // bool xmlConfigGetValue(wxXmlNode *node, const char *attr_name,  wxString &value);
    // void xmlConfigSave(void);

    wxDECLARE_EVENT_TABLE();
};




#endif
